package palms.idserver;

import java.io.IOException;
import java.net.Socket;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SealedObject;

import palms.exceptions.InvalidClassMessage;
import palms.exceptions.InvalidTicketMessage;
import palms.exceptions.InvalidUserMessage;
import palms.messages.SIRequest;
import palms.messages.SIResponse;
import palms.messages.SIServiceInfo;
import palms.messages.SLRequest;
import palms.messages.SLResponse;
import palms.messages.TicketSI;
import palms.security.PalmsSecurityManager;

public class IdWorker implements Runnable {

	private Socket s;
	private IdLogic il;
	
	public IdWorker(Socket s, IdLogic il){
		this.s = s;
		this.il = il;
	}
	
	@Override
	public void run() {
		try {
			
			SIRequest sr = SIRequest.receiveTroughSocket(s);
			processSIRequest(sr);
				
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidClassMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidUserMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidTicketMessage e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}

	public void processSIRequest(SIRequest sireq) throws InvalidKeyException, NoSuchAlgorithmException, IOException, ClassNotFoundException, IllegalBlockSizeException, NoSuchPaddingException, BadPaddingException{
		
		System.out.println("-->Processing a Request");
		
		SealedObject sealed_siticket = sireq.getSiticket();
		SealedObject sealed_sisinfo = sireq.getServiceinfo();
		
		TicketSI siticket = (TicketSI) PalmsSecurityManager.DesealObjectWithK(sealed_siticket, il.getKeySI());
		SIServiceInfo sisinfo = (SIServiceInfo) PalmsSecurityManager.DesealObjectWithK(sealed_sisinfo, siticket.getSessionKey());
		
		System.out.println();
		System.out.println("-->Processing SI Ticket.");
		System.out.println("-->The user \"" + siticket.getUsername() + "\" requested a service.");
		System.out.println("-->The ticket expiring date: " + siticket.getValidity());
		System.out.println("-->Client/SI session key: " + PalmsSecurityManager.asHex(siticket.getSessionKey().getEncoded()));
		
		System.out.println();
		System.out.println("-->Processing SI Info.");
		System.out.println("-->The user \"" + sisinfo.getUsername() + "\" requested a service.");
		System.out.println("-->Time of the request: " + sisinfo.getTimestamp());
		System.out.println("-->SL request: " + sisinfo.getSlservice());
		
		
		if(verifySITicket(siticket, sisinfo)){
			
			try {
				SLRequest slreq = sisinfo.getSlservice();

				Socket ssl = new Socket(il.getSlip(), il.getSlport());
				System.out.println("-->Forwarding request to SL");
				slreq.sendTroughSocket(ssl);

				SLResponse sr = SLResponse.receiveTroughSocket(ssl);
				System.out.println();
				System.out.println("-->Received response");
				System.out.println("-->Sealed SL Service Response:" + sr.getResult());
				ssl.close();

				SealedObject sealed_slresponse = PalmsSecurityManager.SealObjectWithK(sr.getResult(), siticket.getSessionKey());
				SIResponse siresponse = new SIResponse(sealed_slresponse);
				System.out.println("-->Sealed SI Service Response:" + sealed_slresponse);
				System.out.println("-->Sending response to client");
				siresponse.sendTroughSocket(s);

			} catch (InvalidClassMessage e) {
				PalmsSecurityManager.sendError(s, e);
			} catch (InvalidUserMessage e) {
				PalmsSecurityManager.sendError(s, e);
			} catch (InvalidTicketMessage e) {
				PalmsSecurityManager.sendError(s, e);
			}
			
		}else{
			PalmsSecurityManager.sendError(s, new InvalidTicketMessage());
		}
		
		
	}
	
	public boolean verifySITicket(TicketSI ticket, SIServiceInfo info){
		
		if(il.getUserlist().containsKey(ticket.getUsername()) &&
		   ticket.getUsername().equals(info.getUsername()) &&
		   ticket.getIp().equals(s.getInetAddress().getHostAddress()) &&
		   ticket.getValidity() > info.getTimestamp()){
			return true;
		}
		else
			return false;
	}
	
}
